#   This program is free software; you can redistribute it and/or modify
#   it under the terms of the version 3 of the GNU Lesser General Public License
#   as published by the Free Software Foundation.
#
#   This program is distributed in the hope that it will be useful,
#   but WITHOUT ANY WARRANTY; without even the implied warranty of
#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#   GNU General Public License for more details.
#
#   You should have received a copy of the GNU Lesser General Public License
#   along with this program; if not, write to the Free Software
#   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# Copyright (c) NEC Deutschland GmbH, NEC HPC Europe
#
# $Id$

import re
from aggmon.channel import Channel


__all__ = ["LocalChannel"]


class LocalChannel(Channel):
    def __init__( self, url, *args, **kwds ):
        Channel.__init__( self, *args, **kwds )
        self.__subscriber_notify_callbacks = []
        self.url = url
        self.cnt_published = 0
        self.cnt_subscribers = 0
        self.called_subscribers = 0
        self.called_callbacks = {}

    def cleanup( self ):
        for topic, notify_cb in self.__subscriber_notify_callbacks:
            self.unsubscribe( topic, notify_cb )
        del self.__subscriber_notify_callbacks

    # Channel
    def publish( self, topic, message ):
        self.cnt_published += 1
        for (subscriber_topic, subscriber_callback) in self.__subscriber_notify_callbacks:
            pattern = re.sub( r'\.', "\.", subscriber_topic )
            pattern = re.sub( r'\*', "[^\.]*", pattern )
            pattern = re.sub( r'#', ".*", pattern )
            if re.match( pattern, topic ) is not None:
                #print "Matched %s to topic %s\n" % (pattern, topic)
                self.called_subscribers += 1
                cb_name = subscriber_callback.im_class.__name__.split(".")[-1] + "_" + subscriber_callback.__name__
                if cb_name in self.called_callbacks:
                    self.called_callbacks[cb_name] += 1
                else:
                    self.called_callbacks[cb_name] = 1
                #
                # TODO: move this out to be executed in a separate worker thread instead of
                #       doing it inside the publisher. That would also ensure some "serialization".
                subscriber_callback( message, topic=topic )

    def stats( self ):
        return { "url": self.url,
                 "subscribers": self.cnt_subscribers,
                 "published": self.cnt_published,
                 "subscribers_called": self.called_subscribers,
                 "callbacks": self.called_callbacks }

    def subscribe( self, topic, notify_callback ):
        self.cnt_subscribers += 1
        self.__subscriber_notify_callbacks.append( (topic, notify_callback) )

    def unsubscribe( self, topic, notify_callback ):
        self.cnt_subscribers -= 1
        self.__subscriber_notify_callbacks.remove( (topic, notify_callback) )
